package com.daohang361.imqq.hotLoader;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import com.daohang361.imqq.encoder.InterfaceEncoder;

/** 
 * @author naner E-mail:likun3344@163.com 
 * @create time：2011-5-13 下午08:41:36 
 * 创建可以动态更新的java对象<br>  
 * 限制:构造函数不能有参数  
 * 必须实现一个接口  
 * 只能有实例方法(因为接口中不能有静态方法)  
 */  
public class ClassManager {   
	private static Map<String,String> SysAttribute=new HashMap<String,String>();
	private static Map<String,Class>  myClass = new HashMap<String,Class>();
    /**  
     * 保存类路径和时间  
     */  
    private static Map<String,Date> mapModify = new HashMap<String,Date>();   
    /**  
     * 该类被加载时的时间  
     */  
    private static Date firstDate = new Date();   
    
    public static String BathUrl="";
    
    static {
    	 Properties ph = new Properties();
    	 String fileName="conf/sys.properties";
    	 try {
			ph.load(new BufferedReader(new FileReader(new File(fileName))));
			
			Set<Object> keys =ph.keySet();
			for(Iterator<Object> itr = keys.iterator(); itr.hasNext();){
				String key = (String) itr.next();
				SysAttribute.put(key, ph.getProperty(key));
			  }
			
		} catch (Exception e) {
			System.out.println("初始化ClassLoader目录失败。");
		}
		BathUrl=ph.getProperty("pugin_home");
		System.out.println("pugin url："+BathUrl);
    }
  
    /**  
     * 如果class文件重新生成过会自动加载,只有重新创建才会更新  
     *   
     * @param name  
     * @return  
     * @throws InstantiationException  
     * @throws IllegalAccessException  
     * @throws ClassNotFoundException  
     * @throws IOException  
     */  
    public Object getInstance(String name) throws InstantiationException,   
            IllegalAccessException, ClassNotFoundException, IOException {   
    	
    	
//    	  Class c = Class.forName(name);   
//          Class cNew = reloadClass(c);   
//          if (cNew == null) {   
//              cNew = c;   
//          }   
//          Object o = cNew.newInstance();   
//          return o;   

    	Class c = myClass.get(name);
    	
        Class cNew = reloadClass(name);   
        if (cNew == null) {   
        	cNew=c;
        }   
        Object o = cNew.newInstance();   
        return o;   
    }   
  
    /**  
     * 创建代理对象,如果class文件重新生成过会自动加载,调用原先以实例化的方法时也会更新类  
     *   
     * @param name  
     * @return  
     * @throws InstantiationException  
     * @throws IllegalAccessException  
     * @throws ClassNotFoundException  
     * @throws IOException  
     */  
    public Object getInstanceProxy(String name) throws InstantiationException,   
            IllegalAccessException, ClassNotFoundException, IOException {   
        Object target = getInstance(name);   
  
        DynamicProxyFactory factory = new DynamicProxyFactory(   
                new HotInvocationHandler(this));   
  
        return factory.newProxyInstance(target);   
    }   
  
    /**  
     * 重新加载类  
     *   
     * @param c  
     * @return  
     * @throws IOException  2222
     */  
    public synchronized Class reloadClass(String className) throws IOException {   
        Class cNew =null;
//        try {
//        cNew=Class.forName(className);   //存在bug
//		
//        } catch (Exception e) {
//			//e.printStackTrace();
//		}   
        
        System.out.println("check reload:"+className);
        if (hasChanged(className)) { 
        	System.out.println("reloadClass");
        	
				cNew = loadClass(className);
        }   
        return cNew;   
    }   
  
    private boolean hasChanged(String ClassName) throws IOException {   
        boolean isChanged = false;   
        String path =BathUrl.replace("file:", "")+(ClassName.replace(".", "/"))+".class";
        System.out.println("file path:"+path);
        File f = new File(path);   
        if (f.exists()) {   
        	System.out.println("file exists");
            Date newDate = new Date(f.lastModified());   
            Date oldDate = null;   
            String key = f.getCanonicalPath();   
            if (mapModify.containsKey(key)) {   
                oldDate = (Date) mapModify.get(key);   
            }   
            if(oldDate==null)
            	{
            	System.out.println("第一次加载:"+ClassName);
            	isChanged=true;
            	}
            else
            	isChanged = oldDate.compareTo(newDate) < 0;
            
            if (isChanged) {   
                mapModify.put(key, newDate);   
            }   
        }else
        	System.out.println("file not exists");
        return isChanged;   
    }   
  
    private Class loadClass(String className) throws IOException {   
        ClassLoaderAdvisor classLoader = new ClassLoaderAdvisor();   
        Class cNew =classLoader.loadClass(className);
        myClass.remove(className);
        myClass.put(className, cNew);
		return cNew;   
    }   
  
    public Class UrlLoader(String className)
    {
    	 try {
			URL[] externalURLs = new URL[] { new URL(BathUrl) };
			ClassLoader cl = new URLClassLoader(externalURLs);
			return cl.loadClass(className);
		} catch (Exception e) {
			e.printStackTrace();
		}  
		return null;
    }
    public static void main(String[] args) throws IOException,   
            InstantiationException, IllegalAccessException,   
            ClassNotFoundException, InterruptedException {   
        ClassManager manager = new ClassManager();   
        String className = getSysAttribute("test");//"com.daohang361.imqq.hotLoader.Test"; 
        ITest t = (ITest) manager.getInstanceProxy(className);  
        ITest t2 = (ITest) manager.getInstanceProxy(className); 
        System.out.println("t1:"+t);
        System.out.println("t2:"+t2);
        t.set("t");
        t2.set("t2");
        System.out.println("t12:"+t);

        t.test("111");
        t2.test("t2");
        System.out.println("t13:"+t);

        System.out.println("t.toString():"+t.toString());
        int size = 10;   
        int i = 0;   
        while (i < size) {   
            System.out.println(i);   
            i++;   
            Thread.currentThread().sleep(1000);   
        }   
  
        t.test("222");   
        System.out.println("t.toString():"+t.toString());
        i = 0;   
        while (i < size) {   
            System.out.println(i);   
            i++;   
            Thread.currentThread().sleep(1000);   
        }   
  
        t.test("333");   
    }

	public static String getSysAttribute(String key) {
		return SysAttribute.get(key);
	}
}  
